<template>
  <div class="map-page">
    <div class="map-card">
      <h2>🗺️ 地图页面 <span class="subtitle">（远程自动显示）</span></h2>
      <div class="map-actions">
        <button class="back-btn" @click="$router.push('/')">返回主控</button>
        <button class="reset-btn" @click="resetView">重置缩放</button>
      </div>
      <div class="canvas-wrapper">
        <canvas 
          ref="mapCanvas" 
          :width="canvasWidth" 
          :height="canvasHeight"
          @touchstart="handleTouchStart"
          @touchmove="handleTouchMove"
          @touchend="handleTouchEnd"
          @wheel="handleWheel"
          style="touch-action: none;"
        ></canvas>
      </div>
      <div class="tip">
        <br>请先在主控页面连接机器人，地图将自动显示。
      </div>
    </div>
  </div>
</template>

<script>
import ROSLIB from 'roslib';
export default {
  name: 'MapPage',
  props: ['ros', 'isConnected'],
  data() {
      return {
        hasMapData: false,
        mapDataReceived: false,
        scale: 1,
        panX: 0,
        panY: 0,
        lastTouchDistance: 0,
        isPanning: false,
        lastTouchPos: { x: 0, y: 0 },
        originalMapData: null,
        cachedMapImage: null, // 缓存预处理的地图图像
        robotPose2D: null, // 小车位置
        canvasWidth: 800, // 画布宽度
        canvasHeight: 600 // 画布高度
      };
  },
  mounted() {
    // 远程订阅/map
    if (this.ros && this.isConnected) {
      this.mapTopic = new ROSLIB.Topic({
        ros: this.ros,
        name: '/map',
        messageType: 'nav_msgs/msg/OccupancyGrid'
      });
      this.mapTopic.subscribe(this.drawMap);

      // 自动修复：订阅小车位置
      this.pose2DTopic = new ROSLIB.Topic({
        ros: this.ros,
        name: '/amcl_pose',
        messageType: 'geometry_msgs/msg/PoseWithCovarianceStamped'
      });
      this.pose2DTopic.subscribe(this.updateRobotPose2D);
    }
    
    // 监听窗口大小变化
    this.handleResize = () => {
      if (this.originalMapData) {
        this.drawMap(this.originalMapData);
      }
    };
    window.addEventListener('resize', this.handleResize);
  },
  beforeUnmount() {
    if (this.mapTopic) this.mapTopic.unsubscribe();
    if (this.pose2DTopic) this.pose2DTopic.unsubscribe();
    if (this.handleResize) window.removeEventListener('resize', this.handleResize);
  },
  methods: {
    drawMap(map) {
      // 存储原始地图数据
      this.originalMapData = {
        data: map.data,
        info: map.info
      };

      const canvas = this.$refs.mapCanvas;
      const wrapper = canvas.parentElement;
      
      // 计算容器可用宽度（减去padding）
      const wrapperWidth = wrapper.clientWidth - 36; // 减去左右padding
      
      // 保持地图的宽高比，以宽度为准计算高度
      const mapAspectRatio = map.info.width / map.info.height;
      const canvasWidth = wrapperWidth;
      const canvasHeight = wrapperWidth / mapAspectRatio;
      
      // 设置画布大小
      this.canvasWidth = canvasWidth;
      this.canvasHeight = canvasHeight;
      canvas.width = this.canvasWidth;
      canvas.height = this.canvasHeight;

      // 预处理并缓存地图图像
      this.preprocessMapImage(map);
      
      // 绘制缓存的地图和小车位置
      this.renderCachedMap();
    },
    updateRobotPose2D(poseWithCovariance) {
      // 从 PoseWithCovarianceStamped 中提取位置和方向
      const position = poseWithCovariance.pose.pose.position;
      const orientation = poseWithCovariance.pose.pose.orientation;
      
      // 将四元数转换为欧拉角（yaw）
      const yaw = Math.atan2(
        2 * (orientation.w * orientation.z + orientation.x * orientation.y),
        1 - 2 * (orientation.y * orientation.y + orientation.z * orientation.z)
      );
      
      // 转换为期望的格式
      this.robotPose2D = {
        x: position.x,
        y: position.y,
        theta: yaw
      };
      
      console.log('[前端收到/amcl_pose]', this.robotPose2D); // 调试信息
      this.renderCachedMap(); // 触发地图重绘
    },

    // 预处理地图数据，生成缓存图像
    preprocessMapImage(map) {
      // 创建离屏canvas来预处理地图
      const offscreenCanvas = document.createElement('canvas');
      const offscreenCtx = offscreenCanvas.getContext('2d');
      const width = map.info.width;
      const height = map.info.height;
      
      offscreenCanvas.width = width;
      offscreenCanvas.height = height;

      // 创建图像数据
      const imageData = offscreenCtx.createImageData(width, height);
      const data = imageData.data;

      // 处理地图数据，只执行一次
      for (let i = 0; i < map.data.length; i++) {
        let value = map.data[i];
        let color = 205; // 未知
        if (value === 0) color = 255; // 空闲
        else if (value === 100) color = 0; // 障碍
        
        data[i * 4 + 0] = color;
        data[i * 4 + 1] = color;
        data[i * 4 + 2] = color;
        data[i * 4 + 3] = 255;
      }

      // 将处理好的图像数据绘制到离屏canvas
      offscreenCtx.putImageData(imageData, 0, 0);
      
      // 缓存这个预处理的图像
      this.cachedMapImage = offscreenCanvas;
    },

    // 快速渲染缓存的地图（用于缩放和平移）
    renderCachedMap() {
      if (!this.cachedMapImage) return;
      
      const canvas = this.$refs.mapCanvas;
      const ctx = canvas.getContext('2d');

      // 清除画布并填充白色背景
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.fillStyle = '#ffffff';
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      // 保存上下文
      ctx.save();

      // 应用缩放和平移变换
      ctx.translate(canvas.width / 2, canvas.height / 2);
      ctx.scale(this.scale, this.scale);
      ctx.translate(-canvas.width / 2 + this.panX, -canvas.height / 2 + this.panY);

      // 直接绘制缓存的图像，速度很快
      ctx.drawImage(this.cachedMapImage, 0, 0);

      // 绘制小车位置（三角形箭头）
      if (this.robotPose2D && this.originalMapData) {
        const { info } = this.originalMapData;
        // 坐标转换：地图原点、分辨率、画布缩放等
        const mapX = (this.robotPose2D.x - info.origin.position.x) / info.resolution;
        const mapY = info.height - (this.robotPose2D.y - info.origin.position.y) / info.resolution;
        
        ctx.save();
        ctx.translate(mapX, mapY);
        ctx.rotate(this.robotPose2D.theta);
        
        // 三角形箭头参数
        const arrowLength = 8;
        const arrowWidth = 6;
        
        ctx.fillStyle = '#ff4757';
        ctx.strokeStyle = '#cc0000';
        ctx.lineWidth = 2;
        
        ctx.beginPath();
        ctx.moveTo(arrowLength, 0); // 箭头尖端
        ctx.lineTo(-arrowLength/2, -arrowWidth/2); // 尾部左点
        ctx.lineTo(-arrowLength/2, arrowWidth/2); // 尾部右点
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        
        ctx.restore();
      }

      // 恢复上下文
      ctx.restore();
    },

    renderMapWithTransform() {
      // 现在只需要调用快速渲染方法
      this.renderCachedMap();
    },

    // 触摸事件处理
    handleTouchStart(event) {
      event.preventDefault();
      
      if (event.touches.length === 1) {
        // 单指拖拽
        this.isPanning = true;
        const canvas = this.$refs.mapCanvas;
        const rect = canvas.getBoundingClientRect();
        this.lastTouchPos = {
          x: event.touches[0].clientX - rect.left,
          y: event.touches[0].clientY - rect.top
        };
      } else if (event.touches.length === 2) {
        // 双指缩放
        this.isPanning = false;
        const touch1 = event.touches[0];
        const touch2 = event.touches[1];
        this.lastTouchDistance = Math.sqrt(
          Math.pow(touch2.clientX - touch1.clientX, 2) +
          Math.pow(touch2.clientY - touch1.clientY, 2)
        );
      }
    },

    handleTouchMove(event) {
      event.preventDefault();
      
      if (event.touches.length === 1 && this.isPanning) {
        // 单指拖拽
        const canvas = this.$refs.mapCanvas;
        const rect = canvas.getBoundingClientRect();
        const touch = event.touches[0];
        const currentX = touch.clientX - rect.left;
        const currentY = touch.clientY - rect.top;
        
        const deltaX = currentX - this.lastTouchPos.x;
        const deltaY = currentY - this.lastTouchPos.y;
        
        this.panX += deltaX;
        this.panY += deltaY;
        
        this.lastTouchPos = {
          x: currentX,
          y: currentY
        };
        
        this.renderCachedMap();
      } else if (event.touches.length === 2) {
        // 双指缩放
        const touch1 = event.touches[0];
        const touch2 = event.touches[1];
        const currentDistance = Math.sqrt(
          Math.pow(touch2.clientX - touch1.clientX, 2) +
          Math.pow(touch2.clientY - touch1.clientY, 2)
        );
        
        if (this.lastTouchDistance > 0) {
          const scaleFactor = currentDistance / this.lastTouchDistance;
          const newScale = this.scale * scaleFactor;
          
          // 限制缩放范围
          if (newScale >= 0.1 && newScale <= 5) {
            this.scale = newScale;
            this.renderCachedMap();
          }
        }
        
        this.lastTouchDistance = currentDistance;
      }
    },

    handleTouchEnd(event) {
      event.preventDefault();
      this.isPanning = false;
      this.lastTouchDistance = 0;
    },

    // 鼠标滚轮缩放（桌面端）
    handleWheel(event) {
      event.preventDefault();
      
      const scaleFactor = event.deltaY > 0 ? 0.9 : 1.1;
      const newScale = this.scale * scaleFactor;
      
      // 限制缩放范围
      if (newScale >= 0.1 && newScale <= 5) {
        this.scale = newScale;
        this.renderCachedMap();
      }
    },

    // 缩放控制
    zoomIn() {
      const newScale = this.scale * 1.2;
      if (newScale <= 5) {
        this.scale = newScale;
        this.renderCachedMap();
      }
    },

    zoomOut() {
      const newScale = this.scale * 0.8;
      if (newScale >= 0.1) {
        this.scale = newScale;
        this.renderCachedMap();
      }
    },

    resetView() {
      this.scale = 1;
      this.panX = 0;
      this.panY = 0;
      this.renderCachedMap();
    }
  }
};
</script>

<style scoped>
.map-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #1e3c72, #2a5298, #1e3c72);
}
.map-card {
  background: rgba(20, 30, 60, 0.98);
  border-radius: 18px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.25);
  padding: 36px 32px 28px 32px;
  min-width: 800px;
  max-width: 95vw;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.map-card h2 {
  color: #fff;
  font-size: 2rem;
  margin-bottom: 18px;
  font-weight: bold;
  letter-spacing: 1px;
}
.subtitle {
  font-size: 1rem;
  color: #2ed573;
  margin-left: 8px;
}
.map-actions {
  display: flex;
  gap: 18px;
  margin-bottom: 18px;
}
.back-btn {
  background: linear-gradient(45deg, #ff4757, #ff6b7a);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 10px 22px;
  font-size: 1rem;
  font-weight: bold;
  cursor: pointer;
  transition: background 0.2s;
}
.back-btn:hover {
  background: linear-gradient(45deg, #ff6b7a, #ff4757);
}
.reset-btn {
  background: linear-gradient(45deg, #4b6cb7, #6c7ae0);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 10px 22px;
  font-size: 1rem;
  font-weight: bold;
  cursor: pointer;
  transition: background 0.2s;
}
.reset-btn:hover {
  background: linear-gradient(45deg, #6c7ae0, #4b6cb7);
}
.canvas-wrapper {
  background: #222b44;
  border-radius: 12px;
  padding: 18px;
  margin-bottom: 12px;
  box-shadow: 0 2px 12px rgba(0,0,0,0.12);
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 800px;
  min-height: 600px;
  width: 100%;
}
canvas {
  display: block;
  background: #ffffff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  width: 100%;
  height: auto;
}
.tip {
  color: #aaa;
  font-size: 0.98rem;
  margin-top: 10px;
  text-align: center;
}
@media (max-width: 900px) {
  .map-card {
    min-width: 0;
    padding: 16px 4vw 12px 4vw;
  }
  .canvas-wrapper {
    padding: 6px;
    min-width: 90vw;
    min-height: 400px;
  }
}

@media (max-width: 480px) {
  .map-page {
    min-height: 80vh !important;
    padding: 4px !important;
    background: linear-gradient(135deg, #1e3c72, #2a5298, #1e3c72) !important;
    align-items: flex-start !important;
    padding-top: 20px !important;
  }
  
  .map-card {
    min-width: 0 !important;
    max-width: 100vw !important;
    padding: 12px 8px 8px 8px !important;
    border-radius: 12px !important;
    box-shadow: 0 4px 16px rgba(0,0,0,0.3) !important;
    margin: 0 !important;
  }
  
  .map-card h2 {
    font-size: 1.2rem !important;
    margin-bottom: 12px !important;
    letter-spacing: 0.5px !important;
    text-align: center !important;
  }
  
  .subtitle {
    font-size: 0.8rem !important;
    margin-left: 4px !important;
    display: block !important;
    margin-top: 2px !important;
  }
  
  .map-actions {
    gap: 12px !important;
    margin-bottom: 12px !important;
    justify-content: center !important;
  }
  
  .back-btn {
    padding: 8px 16px !important;
    font-size: 0.9rem !important;
    border-radius: 6px !important;
    min-width: 80px !important;
  }
  
  .reset-btn {
    padding: 8px 16px !important;
    font-size: 0.9rem !important;
    border-radius: 6px !important;
    min-width: 80px !important;
  }
  
  .canvas-wrapper {
    padding: 4px !important;
    min-width: calc(100vw - 32px) !important;
    min-height: 300px !important;
    /* max-height: 10vh !important; */
    border-radius: 8px !important;
    box-shadow: 0 2px 8px rgba(0,0,0,0.2) !important;
    overflow: hidden !important;
  }
  
  canvas {
    border-radius: 6px !important;
    max-width: 100% !important;
    max-height: 100% !important;
    object-fit: contain !important;
  }
  
  .tip {
    font-size: 0.8rem !important;
    margin-top: 8px !important;
    padding: 0 8px !important;
    line-height: 1.4 !important;
  }
}
</style> 